﻿/*************************************************************************************************************
  Copyright (c) 2010, Zack Evans
  All rights reserved.

  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of CapriSoft nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
  OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
**************************************************************************************************************/
using System;
using System.Collections.Generic;
using System.Data;
using System.Windows.Forms;
using DataAccess;
using System.ComponentModel;
using Extention;

namespace ExtentionFormApp
{
    public partial class Form1 : Form
    {
        private object currentObject = null;
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
           
        }

        private DataSet CreateDummyDataSet()
        {
            DataSet _dataset = new DataSet();
            DataTable _table = new DataTable();
            _dataset.Tables.Add(_table);
            _table.Columns.Add("Id");
            _table.Columns.Add("Code");
            _table.Columns.Add("Caption");

            DataRow newRow = _dataset.Tables[0].NewRow();
            newRow["Id"] = "1";
            newRow["Code"] = "001";
            newRow["Caption"] = "Cheese Burger";
            _dataset.Tables[0].Rows.Add(newRow);

            DataRow newRow2 = _dataset.Tables[0].NewRow();
            newRow2["Id"] = "2";
            newRow2["Code"] = "002";
            newRow2["Caption"] = "Double Cheese Burger";
            _dataset.Tables[0].Rows.Add(newRow2);

            return _dataset;
        }
        private ListEx<Person> GenerateItems()
        {
            Person person1 = new Person()
            {
                IdNumber = 1003121542086,
                FirstName = "Zack",
                Surname = "Evans",
                Age = 31
            }; 
            Person person2 = new Person()
            {
                IdNumber = 1003746542085,
                FirstName = "Anell",
                Surname = "Evans",
                Age = 5
            }; 
            Person person3 = new Person()
            {
                IdNumber = 1000050000,
                FirstName = "John",
                Surname = "Doe",
                Age = 20
            }; 
            Person person4 = new Person()
            {
                IdNumber = 1000060000,
                FirstName = "Jane",
                Surname = "Doe",
                Age = 19
            };

            ListEx<Person> personList = new ListEx<Person>();
            personList.Add(person1);
            personList.Add(person2);
            personList.Add(person3);
            personList.Add(person4);
            return personList;
        }

        private void btnSqlDataReading_Click(object sender, EventArgs e)
        {
            //The create database script is contained within the factory class
            //please create or use your own database to run this sample.

            dataView.DataSource = null;

            //use the factory class to create some connection
            string connectionString =
                Factory.MakeConnectionString("CapriSoft", "ListExDb", true);

            //use the connection string and create your IConnection 
            using (IConnection connection =
                Factory.CreateConnection(AdapterTypes.SqlConnection, connectionString))
            {
                try
                {
                    connection.Open();

                    //create a command from your connection
                    ICommand command =
                        (ICommand)connection.CreateCommand();

                    //set your sql text to be executed
                    command.CommandText = "select * from dbo.Person";

                    //set the command type
                    command.CommandType = CommandType.Text;

                    //note that the SqlCommand returns a IDataReader
                    //this is actually the ListEx implementation
                    //explore this object and you will find the dynamically created types
                    ListEx<GenericDataObject> dynamicAssemblyList = new ListEx<GenericDataObject>(
                        command.ExecuteReader());

                    dynamicAssemblyList.Fill();

                    //this is also valid, passing the IDataReader through to the constructor
                    dynamicAssemblyList =
                        new ListEx<GenericDataObject>(dynamicAssemblyList.CreateDataSet().CreateDataReader());

                    dynamicAssemblyList.Fill();

                    //lets a look at the object in the list
                    object obj = (dynamicAssemblyList.Count > 0) ? dynamicAssemblyList[0] : default(GenericDataObject);

                    //type is our dynamic IDataObject
                    Type objType = (obj != null) ? obj.GetType() : default(Type);

                    //we use a TypeDescriptor to extract the properties
                    PropertyDescriptorCollection collection =
                        (obj != null) ? TypeDescriptor.GetProperties(obj) : default(PropertyDescriptorCollection);

                    //just to make sure, we have something to look at
                    if (collection != null && collection.Count > 0)
                    {
                        foreach (PropertyDescriptor property in collection)
                        {
                            //now this will provide on our property name
                            string PropertyName = property.Name;

                            //now this will provide on our property type
                            Type PropertType = property.PropertyType;

                            //lastly, this will provide on our property value
                            object PropertyValue = property.GetValue(obj);
                        }
                    }

                    //done to display our results.
                    DataSet dataSet = dynamicAssemblyList.CreateDataSet();
                    dataView.DataSource = dataSet.Tables[0];
                    dataView.Focus();

                    currentObject = dynamicAssemblyList;
                    dataView_RowEnter(this, new DataGridViewCellEventArgs(0, 0));                    

                }
                catch (Exception ex) { MessageBox.Show(ex.Message); }
                finally
                {
                    connection.Close();
                }
            }
        }
        private void btnListRead_Click(object sender, EventArgs e)
        {
            dataView.DataSource = null;
            //create a fictious list of people
            using (ListEx<Person> ListofPersons = GenerateItems())
            {
                int x = 0;
                //use the datareader read method to initialize a forward read
                while (ListofPersons.Read())
                {
                    //extract the IdNumber by type using the IDataReader calls
                    Int64 IdNumber = ListofPersons.GetInt64(0);
                    
                    //validate the result by accessing the collection through its indexer
                    if (IdNumber == ListofPersons[x].IdNumber)
                        Console.WriteLine("are equal");

                    string FirstName = ListofPersons.GetString(1);
                    if (FirstName == ListofPersons[x].FirstName)
                        Console.WriteLine("are equal");

                    string Surname = ListofPersons.GetString(2);
                    if (Surname == ListofPersons[x].Surname)
                        Console.WriteLine("are equal");

                    int Age = ListofPersons.GetInt32(3);
                    if (Age == ListofPersons[x].Age)
                        Console.WriteLine("are equal");

                    x++;
                }
                ListofPersons.Close();
            }
        }
        private void btnListCreateDataSet_Click(object sender, EventArgs e)
        {
            dataView.DataSource = null;
            //create a fictious list of people
            ListEx<Person> ListofPersons = GenerateItems();

            //call the CreateDataSet function of the list, in effect it will return a
            //.net dataset using the list information for its record source
            DataSet dataSet = ListofPersons.CreateDataSet("ListofPersonsSet", "ListofPersons");

            //set the grid view datasource
            dataView.DataSource = dataSet.Tables[0];

            currentObject = ListofPersons;
            dataView_RowEnter(this, new DataGridViewCellEventArgs(0, 0));
        }
        private void btnDynamicAssembly_Click(object sender, EventArgs e)
        {
            dataView.DataSource = null;
            //create a fictious list of people
            using (ListEx<Person> ListofPersons = GenerateItems())
            {
                //call the CreateDataSet function of the list, in effect it will return a
                //.net dataset using the list information for its record source
                DataSet dataSet = ListofPersons.CreateDataSet("ListofPersonsSet", "ListofPersons");
                dataView.DataSource = dataSet.Tables[0];
               
                //using the dataset create data reader method. initialize a new
                //ListEx with passing through the IDataReader from the dataset.
                ListEx<object> listofPeople = new ListEx<object>(dataSet.CreateDataReader());
                listofPeople.Fill();

                currentObject = listofPeople;
                dataView_RowEnter(this, new DataGridViewCellEventArgs(0, 0));

                //search for a property value
                List<object> findZack = new List<object>(listofPeople.FindByValue("FirstName", "Zack"));

                //search for a property value
                List<object> listAllEvans = new List<object>(listofPeople.FindByValue("Surname", "Evans"));
                while (listofPeople.Read())//travers through forward reading using the IDataReader methods
                {
                    //read in the property of the current record.
                    Int64 IdNumber = listofPeople.GetInt64(0);
                    string FirstName = listofPeople.GetString(1);
                    string Surname = listofPeople.GetString(2);
                    int Age = listofPeople.GetInt32(3);
                    object objectData = listofPeople.GetValue(0);
                }

            }
        }
        private void btnDynamicAssembly2_Click(object sender, EventArgs e)
        {
            dataView.DataSource = null;

            //create a new dataset, note that no type exists with these column properties
            using (DataSet _dataset = CreateDummyDataSet())
            {
                dataView.DataSource = _dataset.Tables[0];

                //initialize the ListEx with by passing through the IDataReader
                ListEx<object> genericConstruct = new ListEx<object>(_dataset.CreateDataReader());
                genericConstruct.Fill();
                //query the dynamic assembly, using reflection to validate
                List<object> code = new List<object>(genericConstruct.FindByValue("Caption", "Cheese Burger"));

                currentObject = genericConstruct;
                dataView_RowEnter(this, new DataGridViewCellEventArgs(0, 0));

            }
        }
        private void btnMapKnown_Click(object sender, EventArgs e)
        {
            //The create database script is contained within the factory class
            //please create or use your own database to run this sample.

            dataView.DataSource = null;

            //use the factory class to create some connection
            string connectionString =
                Factory.MakeConnectionString("CapriSoft", "ListExDb", true);

            //use the connection string and create your IConnection 
            using (IConnection connection =
                Factory.CreateConnection(AdapterTypes.SqlConnection, connectionString))
            {
                try
                {
                    connection.Open();

                    //create a command from your connection
                    ICommand command =
                        (ICommand)connection.CreateCommand();

                    //set your sql text to be executed
                    command.CommandText = "select * from dbo.Person";

                    //set the command type
                    command.CommandType = CommandType.Text;

                    //note that the SqlCommand returns a IDataReader
                    //this is actually the ListEx implementation
                    //explore this object and you will find the dynamically created types
                    ListEx<GenericDataObject> dynamicAssemblyList =
                        new ListEx<GenericDataObject>(
                        command.ExecuteReader());

                    //causes the list to be populated
                    dynamicAssemblyList.Fill();

                    DataSet dataSet = null;

                    //this example will map the object to a specific object type
                    ListEx<Person> _strongTypedynamicAssemblyList =
                        new ListEx<Person>(command.ExecuteReader(), typeof(Person));                    

                    //causes the list to be populated
                    _strongTypedynamicAssemblyList.Fill();

                    //second level inheritence example of contactPerson
                    ListEx<ContactPerson> contactList =
                       new ListEx<ContactPerson>(command.ExecuteReader(), typeof(ContactPerson));

                    contactList.Fill();

                    int countRecords = contactList.Count;

                    //second level inheritence example of contactPerson, with passing the first contact 
                    //list in as a reader object
                    ListEx<ContactPerson> contactListIn =
                       new ListEx<ContactPerson>(contactList, typeof(ContactPerson));

                    //note the relevance of what is happening here,
                    //this contactList inherits from Person, but includes the additional Email property
                    //the property is not mapped but displayed in the datagrid for the example.
                    contactListIn.Fill();

                    countRecords = contactList.Count;

                    if (countRecords > 0)
                        contactListIn[0].Email = "z.evans@caprisoft.co.za";

                    //lets a look at the object in the list
                    object obj = (dynamicAssemblyList.Count > 0) ? dynamicAssemblyList[0] : default(object);

                    //type is our dynamic IDataObject
                    Type objType = (obj != null) ? obj.GetType() : default(Type);

                    //we use a TypeDescriptor to extract the properties
                    PropertyDescriptorCollection collection =
                        (obj != null) ? TypeDescriptor.GetProperties(obj) : default(PropertyDescriptorCollection);

                    //just to make sure, we have something to look at
                    if (collection != null && collection.Count > 0)
                    {
                        foreach (PropertyDescriptor property in collection)
                        {
                            //now this will provide on our property name
                            string PropertyName = property.Name;

                            //now this will provide on our property type
                            Type PropertType = property.PropertyType;

                            //lastly, this will provide on our property value
                            object PropertyValue = property.GetValue(obj);
                        }
                    }

                    //done to display our results.
                    dataSet = contactListIn.CreateDataSet();
                    dataView.DataSource = dataSet.Tables[0];

                    currentObject =  contactListIn;
                    dataView_RowEnter(this, new DataGridViewCellEventArgs(0, 0));
                }
                catch (Exception ex) { MessageBox.Show(ex.Message); }
                finally
                {
                    connection.Close();
                }
            }
        }
        private void btnSqlDbCasting_Click(object sender, EventArgs e)
        {
            //The create database script is contained within the factory class
            //please create or use your own database to run this sample.

            dataView.DataSource = null;

            //use the factory class to create some connection
            string connectionString =
                Factory.MakeConnectionString("CapriSoft", "ListExDb", true);

            //use the connection string and create your IConnection 
            using (IConnection connection =
                Factory.CreateConnection(AdapterTypes.SqlConnection, connectionString))
            {
                try
                {
                    connection.Open();

                    //create a command from your connection
                    ICommand command =
                        (ICommand)connection.CreateCommand();

                    //set your sql text to be executed
                    command.CommandText = "select * from dbo.Person";

                    //set the command type
                    command.CommandType = CommandType.Text;

                    //note that the SqlCommand returns a IDataReader
                    //this is actually the ListEx implementation
                    //explore this object and you will find the dynamically created types
                    ListEx<GenericDataObject> dynamicAssemblyList = 
                        (ListEx<GenericDataObject>)command.ExecuteReader();

                    dynamicAssemblyList.Fill();

                    //this is also valid, passing the IDataReader through to the constructor
                    dynamicAssemblyList =
                        new ListEx<GenericDataObject>(dynamicAssemblyList.CreateDataSet().CreateDataReader());

                    dynamicAssemblyList.Fill();

                    //lets a look at the object in the list
                    object obj = (dynamicAssemblyList.Count > 0) ? dynamicAssemblyList[0] : default(GenericDataObject);

                    //type is our dynamic IDataObject
                    Type objType = (obj != null) ? obj.GetType() : default(Type);

                    //we use a TypeDescriptor to extract the properties
                    PropertyDescriptorCollection collection =
                        (obj != null) ? TypeDescriptor.GetProperties(obj) : default(PropertyDescriptorCollection);

                    //just to make sure, we have something to look at
                    if (collection != null && collection.Count > 0)
                    {
                        foreach (PropertyDescriptor property in collection)
                        {
                            //now this will provide on our property name
                            string PropertyName = property.Name;

                            //now this will provide on our property type
                            Type PropertType = property.PropertyType;

                            //lastly, this will provide on our property value
                            object PropertyValue = property.GetValue(obj);
                        }
                    }

                    //done to display our results.
                    DataSet dataSet = dynamicAssemblyList.CreateDataSet();
                    dataView.DataSource = dataSet.Tables[0];

                    currentObject = dynamicAssemblyList;
                    dataView_RowEnter(this, new DataGridViewCellEventArgs(0, 0));
                }
                catch (Exception ex) { MessageBox.Show(ex.Message); }
                finally
                {
                    connection.Close();
                }
            }
        }

        private void dataView_RowEnter(object sender, DataGridViewCellEventArgs e)
        {
            if (currentObject == null)
                return;

            Type genericType = currentObject.GetType().GetGenericArguments()[0];

            if (genericType.Equals(typeof(object)))
            {
                if (((ListEx<object>)currentObject) != null)
                    propertyGrid.SelectedObject = (((ListEx<object>)currentObject).Count > e.RowIndex) ? ((ListEx<object>)currentObject)[e.RowIndex] : null;
                else propertyGrid.SelectedObject = null;
            }
            else if (genericType.Equals(typeof(GenericDataObject)))
            {
                if (((ListEx<GenericDataObject>)currentObject) != null)
                    propertyGrid.SelectedObject = (((ListEx<GenericDataObject>)currentObject).Count > e.RowIndex) ? ((ListEx<GenericDataObject>)currentObject)[e.RowIndex] : null;
                else propertyGrid.SelectedObject = null;
            }
            else if (genericType.Equals(typeof(Person)))
            {
                if (((ListEx<Person>)currentObject) != null)
                    propertyGrid.SelectedObject = (((ListEx<Person>)currentObject).Count > e.RowIndex) ? ((ListEx<Person>)currentObject)[e.RowIndex] : null;
                else propertyGrid.SelectedObject = null;
            }
            else if (genericType.Equals(typeof(ContactPerson)))
            {
                if (((ListEx<ContactPerson>)currentObject) != null)
                    propertyGrid.SelectedObject = (((ListEx<ContactPerson>)currentObject).Count > e.RowIndex) ? ((ListEx<ContactPerson>)currentObject)[e.RowIndex] : null;
                else propertyGrid.SelectedObject = null;
            }

            if (propertyGrid.SelectedObject != null)
               _classCode.Text =
                   ReflectHelper.SimpleCode(propertyGrid.SelectedObject.GetType());
        }
        private void dataView_DataSourceChanged(object sender, EventArgs e)
        {
            propertyGrid.SelectedObject = null;
            _classCode.Text = "";
        }
        private void btnFunkySql_Click(object sender, EventArgs e)
        {
              string connectionString =
                Factory.MakeConnectionString("CapriSoft", "ListExDb", true);

              //use the connection string and create your IConnection 
              using (IConnection connection =
                  Factory.CreateConnection(AdapterTypes.SqlConnection, connectionString))
              {
                  try
                  {
                      connection.Open();

                      //create a command from your connection
                      ICommand command =
                          (ICommand)connection.CreateCommand();

                      //set your sql text to be executed
                      command.CommandText = "select * from dbo.Person";

                      //set the command type
                      command.CommandType = CommandType.Text;

                      ListEx<ContactPerson> people = new ListExCommand<ContactPerson>(command)
                      .Map(p=> new ContactPerson()
                      {
                          Age = p.GetInt32(p.GetOrdinal("Age")),
                          FirstName = p.GetString(p.GetOrdinal("FirstName")),
                          IdNumber = p.GetInt64(p.GetOrdinal("IdNumber")),
                          Surname = p.GetString(p.GetOrdinal("Surname")),
                          Email = "z.evans@caprisoft.co.za"
                      })
                      .ToListEx()
                      .Where("FirstName", "Peter");

                      //done to display our results.
                      DataSet dataSet = people.CreateDataSet();
                      dataView.DataSource = dataSet.Tables[0];

                      currentObject = people;
                      dataView_RowEnter(this, new DataGridViewCellEventArgs(0, 0));

                  }
                  catch (Exception ex)
                  {
                      MessageBox.Show(ex.Message);
                  }
              }

        }
        private void btnListExConvert_Click(object sender, EventArgs e)
        {
            ListEx<Person> personList = GenerateItems();
            //map the person list to a contact list
            ListEx<ContactPerson> people = new ListExAutoMap<ContactPerson, Person>(personList)
            .Map(p => new ContactPerson()
            {
                Age = p.Age,
                FirstName = p.FirstName,
                IdNumber = p.IdNumber,
                Surname = p.Surname,
                Email = string.Empty
            })
            .ToListEx();

            Console.WriteLine(String.Format("collection returned {0} results", people.Count.ToString()));
            
            //returns an enumerator that is be passed as argument to construct the new list
            people = new ListEx<ContactPerson>
            (
                new ListExAutoMap<ContactPerson, Person>(personList)
                    .Map(p => new ContactPerson()
                    {
                        Age = p.Age,
                        FirstName = p.FirstName,
                        IdNumber = p.IdNumber,
                        Surname = p.Surname,
                        Email = "z.evans@caprisoft.co.za"
                    })
                    .ToListEx()
                    .WhereEnumerator(contactPerson => contactPerson.Surname == "Evans")
            );          

            //or simple just let the AutoMap convert for you
            people = new ListExAutoMap<ContactPerson, Person>(personList)
            .Map(p => new ContactPerson()
            {
                Age = p.Age,
                FirstName = p.FirstName,
                IdNumber = p.IdNumber,
                Surname = p.Surname,
                Email = "z.evans@caprisoft.co.za"
            })
            .ToListEx()
            .Where(contactPerson => contactPerson.FirstName == "Zack");

            //done to display our results.
            DataSet dataSet = people.CreateDataSet();
            dataView.DataSource = dataSet.Tables[0];

            currentObject = people;
            dataView_RowEnter(this, new DataGridViewCellEventArgs(0, 0));

            Console.WriteLine(String.Format("collection returned {0} results", people.Count.ToString()));

        }

       
    }

    /// <summary>
    /// the person class inherits from the generic data object class
    /// this is required for dynamic assemblies constructed from data readers
    /// </summary>
    public class Person : GenericDataObject
    {
        [ReadableProperty("IdNumber",true)]
        public long IdNumber { get; set; }

        [ReadableProperty()]
        public string FirstName { get; set; }

        [ReadableProperty()]
        public string Surname { get; set; }

        [ReadableProperty()]
        public int Age { get; set; }

    }
    public class ContactPerson : Person
    {
        [ReadableProperty(Name = "Email")]
        public string Email { get; set; }
    }
}
